
using System;
using System.IO;
using DsUi;
using Godot;

/// <summary>
/// 用于在预制场景中创建 ActivityObject
/// </summary>
[Tool]
public partial class ActivityInstance : Node2D
{
    private const string GroupName = "Editor";
    
    /// <summary>
    /// 物体Id
    /// </summary>
    [Export]
    public string Id
    {
        get => _id;
        set
        {
            _id = value;
            _dirty = true;
        }
    }

    /// <summary>
    /// 默认所在层级
    /// </summary>
    [Export]
    public RoomLayerEnum DefaultLayer { get; set; } = RoomLayerEnum.NormalLayer;

    /// <summary>
    /// 是否显示阴影
    /// </summary>
    [Export]
    public bool ShowShadow
    {
        get => _showShadow;
        set
        {
            _showShadow = value;
            if (_activityObject != null)
            {
                if (value)
                {
                    _activityObject.ShowShadowSprite();
                }
                else
                {
                    _activityObject.HideShadowSprite();
                }
            }
        }
    }

    /// <summary>
    /// 阴影偏移
    /// </summary>
    [Export]
    public Vector2 ShowOffset
    {
        get => _showOffset;
        set
        {
            _showOffset = value;
            if (_activityObject != null)
            {
                _activityObject.ShadowOffset = value;
            }
        }
    }

    /// <summary>
    /// 初始海拔高度
    /// </summary>
    [Export]
    public float Altitude
    {
        get => _altitude;
        set
        {
            _altitude = value;
            if (_activityObject != null)
            {
                _activityObject.Altitude = value;
                _activityObject.Collision.Position = _collPos;
                _activityObject.UpdateShadowSprite((float)GetProcessDeltaTime());
                _activityObject.CalcThrowAnimatedPosition();
            }
        }
    }

    /// <summary>
    /// 动画精灵的z轴索引
    /// </summary>
    [Export]
    public int SpriteZIndex
    {
        get => _spriteZIndex;
        set
        {
            _spriteZIndex = value;
            if (_activityObject != null)
            {
                _activityObject.AnimatedSprite.ZIndex = value;
            }
        }
    }
    
    /// <summary>
    /// 阴影z轴索引
    /// </summary>
    [Export]
    public int ShadowZIndex
    {
        get => _shadowZIndex;
        set
        {
            _shadowZIndex = value;
            if (_activityObject != null)
            {
                _activityObject.ShadowSprite.ZIndex = value;
            }
        }
    }
    
    /// <summary>
    /// 是否启用垂直运动模拟
    /// </summary>
    [Export]
    public bool VerticalMotion { get; private set; } = true;

    /// <summary>
    /// 是否启用碰撞器
    /// </summary>
    [Export]
    public bool CollisionEnabled
    {
        get => _collisionEnabled;
        set
        {
            _collisionEnabled = value;
            if (_activityObject != null)
            {
                _activityObject.Collision.Disabled = !value;
            }
        }
    }
    
    /// <summary>
    /// 编辑器属性, 物体子碰撞器在编辑器中是否可见
    /// </summary>
    [Export]
    public bool CollisionVisible
    {
        get => _collisionVisible;
        set
        {
            _collisionVisible = value;
            OnChangeCollisionVisible();
        }
    }

    private bool _dirty = false;
    private bool _collisionVisible = true;
    private string _prevId;
    private string _id;
    private ActivityObject _activityObject;
    private Sprite2D _errorSprite;
    private bool _showShadow = true;
    private Vector2 _showOffset = new Vector2(0, 2);
    private float _altitude;
    private int _spriteZIndex = 0;
    private int _shadowZIndex = -1;
    private bool _collisionEnabled = true;

    private Vector2 _collPos;
    private bool _createFlag = false;
    
    //嵌套Instance相关
    private bool _isNested = false;
    private ActivityObject _activityInstance;
    
    private static string _jsonText;

    /// <summary>
    /// 清空缓存的json
    /// </summary>
    public static void ClearCacheJson()
    {
        _jsonText = null;
    }
//     
//     public override void _Ready()
//     {
// #if TOOLS
//         if (!Engine.IsEditorHint())
//         {
// #endif
//             var world = World.Current;
//             if (world != null && world.YSortLayer != null && world.NormalLayer != null)
//             {
//                 DoCreateObject();
//             }
// #if TOOLS
//         }
// #endif
//     }
//
//     public override void _Process(double delta)
//     {
// #if TOOLS
//         if (Engine.IsEditorHint())
//         {
//             if (_dirty || (_activityObject != null && _activityObject.GetParent() != this))
//             {
//                 _dirty = false;
//                 
//                 if (_prevId != _id)
//                 {
//                     OnChangeActivityId(_id);
//                 }
//                 else if (string.IsNullOrEmpty(_id))
//                 {
//                     ShowErrorSprite();
//                 }
//
//                 OnChangeCollisionVisible();
//             }
//
//             if (_activityObject != null)
//             {
//                 _activityObject.Collision.Position = _collPos;
//                 _activityObject.UpdateShadowSprite((float)delta);
//                 _activityObject.CalcThrowAnimatedPosition();
//             }
//         }
//         else
//         {
// #endif
//             var world = World.Current;
//             if (world != null && world.YSortLayer != null && world.NormalLayer != null)
//             {
//                 DoCreateObject();
//             }
// #if TOOLS
//         }
// #endif
//     }
//
//     public override void _EnterTree()
//     {
// #if TOOLS
//         if (Engine.IsEditorHint())
//         {
//             _dirty = true;
//             
//             var children = GetChildren();
//             foreach (var child in children)
//             {
//                 if (child is ActivityObject)
//                 {
//                     child.QueueFree();
//                 }
//             }
//             if (_activityObject != null)
//             {
//                 _activityObject.QueueFree();
//             }
//             _activityObject = null;
//             _prevId = null;
//         }
// #endif
//     }
//
//     public override void _ExitTree()
//     {
// #if TOOLS
//         if (Engine.IsEditorHint() && _activityObject != null)
//         {
//             _activityObject.QueueFree();
//             _activityObject = null;
//         }
// #endif
//     }

    private ActivityObject DoCreateObject()
    {
        if (_createFlag)
        {
            return _activityInstance;
        }

        _createFlag = true;
        var activityObject = ActivityObject.Create(Id);
        if (_isNested)
        {
            activityObject.Position = Position - new Vector2(0, 1);
            activityObject.Scale = Scale;
            activityObject.Rotation = Rotation;
        }
        else
        {
            activityObject.Position = GlobalPosition + new Vector2(0, 1);
            activityObject.Scale = GlobalScale;
            activityObject.Rotation = GlobalRotation;
        }
        
        activityObject.Visible = Visible;
        activityObject.ShadowOffset = _showOffset;
        activityObject.Altitude = _altitude;
        activityObject.AnimatedSprite.ZIndex = _spriteZIndex;
        activityObject.ShadowSprite.ZIndex = _shadowZIndex;
        activityObject.EnableVerticalMotion = VerticalMotion;
        activityObject.Collision.Disabled = !_collisionEnabled;
        if (!_isNested)
        {
            activityObject.PutDown(DefaultLayer, _showShadow);
        }
        else
        {
            activityObject.DefaultLayer = DefaultLayer;
            activityObject.ShowShadowSprite();
        }

        var children = GetChildren();
        foreach (var child in children)
        {
            if (!child.IsInGroup(GroupName))
            {
                if (child is ActivityInstance o)
                {
                    o._isNested = true;
                    var instance = o.DoCreateObject();
                    activityObject.AddChild(instance);
                    if (instance is IMountItem mountItem)
                    {
                        activityObject.AddMountObject(mountItem);
                    }
                    else if (instance is IDestroy destroy)
                    {
                        activityObject.AddDestroyObject(destroy);
                    }
                }
                else
                {
                    child.Reparent(activityObject);
                    if (child is Node2D node2D && activityObject.GetCurrentTexture().GetHeight() % 2 == 0)
                    {
                        node2D.Position += new Vector2(0, 1);
                    }
                }
            }
        }

        QueueFree();
        _activityInstance = activityObject;
        return  activityObject;
    }

    private void OnChangeActivityId(string id)
    {
        _prevId = id;

        if (_activityObject != null)
        {
            _activityObject.QueueFree();
            _activityObject = null;
        }

        if (string.IsNullOrEmpty(id))
        {
            ShowErrorSprite();
            return;
        }

        if (_jsonText == null)
        {
            _jsonText = File.ReadAllText("resource/config/ActivityBase.json");
        }
        var str = $"\"Id\": \"{id}\",";
        var index = _jsonText.IndexOf(str, StringComparison.Ordinal);
        if (index > -1)
        {
            const string s = "\"Prefab\": \"";
            var startIndex = _jsonText.IndexOf(s, index, StringComparison.Ordinal);
            if (startIndex > -1)
            {
                var endIndex = _jsonText.IndexOf('"', startIndex + s.Length + 1);
                if (endIndex > -1)
                {
                    var prefab = _jsonText.Substring(startIndex + s.Length, endIndex - (startIndex + s.Length));
                    var instance = ResourceManager.LoadAndInstantiate<ActivityObject>(prefab);
                    _activityObject = instance;
                    _collPos = instance.Collision.Position - instance.AnimatedSprite.Position - instance.AnimatedSprite.Offset;
                    instance.IsCustomShadowSprite = instance.ShadowSprite.Texture != null;
                    instance.Altitude = _altitude;
                    instance.ShadowOffset = _showOffset;
                    _activityObject.Position = _activityObject.AnimatedSprite.Position;
                    if (_showShadow)
                    {
                        instance.ShowShadowSprite();
                        var shadowSpriteMaterial = instance.ShadowSprite.Material as ShaderMaterial;
                        if (shadowSpriteMaterial != null)
                        {
                            shadowSpriteMaterial.SetShaderParameter(
                                ShaderParamNames.ShowOutline,
                                ((ShaderMaterial)instance.AnimatedSprite.Material).GetShaderParameter(ShaderParamNames
                                    .ShowOutline)
                            );
                        }
                    }
                    AddChild(instance);
                    MoveChild(instance, 0);
                    HideErrorSprite();
                    return;
                }
            }
        }
        GD.PrintErr($"未找到Id为'{id}'的物体!");
        ShowErrorSprite();
    }

    private void OnChangeCollisionVisible()
    {
        if (_activityObject != null)
        {
            Utils.EachNode(_activityObject, node =>
            {
                if (node is CollisionShape2D collisionShape2D)
                {
                    collisionShape2D.Visible = _collisionVisible;
                }
                else if (node is CollisionPolygon2D collisionPolygon2D)
                {
                    collisionPolygon2D.Visible = _collisionVisible;
                }
            });
        }
    }

    private void ShowErrorSprite()
    {
        if (_errorSprite == null)
        {
            _errorSprite = new Sprite2D();
            _errorSprite.AddToGroup(GroupName);
            _errorSprite.Texture = ResourceManager.LoadTexture2D(ResourcePath.resource_sprite_ui_commonIcon_Error_png);
            AddChild(_errorSprite);
            MoveChild(_errorSprite, GetChildCount() - 1);
        }
    }

    private void HideErrorSprite()
    {
        if (_errorSprite != null)
        {
            _errorSprite.QueueFree();
            _errorSprite = null;
        }
    }
}
